package com.gwtjs.icustom.controller.install;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.gwtjs.icustom.construct.AmbariInstallStepName;
import com.gwtjs.icustom.construct.AppConstruct;
import com.gwtjs.icustom.construct.AppTypeConstruct;
import com.gwtjs.icustom.entity.DatabaseSchema;
import com.gwtjs.icustom.entity.ResultWrapper;
import com.gwtjs.icustom.ioutils.ExecuteShell;
import com.gwtjs.icustom.ioutils.SQLScriptExecutor;
import com.gwtjs.icustom.mapper.AmbariInstallInfoMapper;
import com.gwtjs.icustom.mapper.AppMapper;
import com.gwtjs.icustom.mapper.ServerHostMapper;
import com.gwtjs.icustom.pojo.AmbariInstallInfo;
import com.gwtjs.icustom.pojo.App;
import com.gwtjs.icustom.pojo.ServerHost;
import com.gwtjs.icustom.utils.JScpUtil;
import com.gwtjs.icustom.utils.LinuxIPUtil;
import com.gwtjs.icustom.utils.ShellUtil;

@RestController
@RequestMapping("/ambari")
public class InstallAmbariController {

    private final static Logger logger = LoggerFactory.getLogger(InstallAmbariController.class);

    @Autowired
    private ServerHostMapper serverHostMapper;
    @Autowired
    private AppMapper appMapper;
    @Autowired
    private AmbariInstallInfoMapper installInfoMapper;

    @Value("${app.work.home}")
    private String workHome;

    @Value("${root.db.password}")
    private String rootDBPassword;
    
    public final static String DRIVER_NAME = "mysql-connector-java-5.1.41-bin.jar";
    public final static String DRIVER_PATH = "/usr/share/java";

    /**
     * <h2>自动安装工具</h2>
     * <p><ul><ol><li>yum源 </li>
     * <li>jdk1.8</li>
     * <li>系统lib</li></ol></ul></p>
     *
     * @throws Exception
     */
    @PutMapping("/autoStart")
    public ResultWrapper autoStart(@RequestBody ServerHost server) throws Exception {
        logger.info("\n开始自动安装.......ambari-server节点：{}........\n", server.getHostIp());
        AmbariInstallInfo info = new AmbariInstallInfo();

        ResultWrapper result = this.createDatabase();
        logger.info("\n创建数据库 ：{}", result.getStatus());
        info.setActive(1);
        info.setAmbariIp(server.getHostIp());
        info.setStepName(AmbariInstallStepName.CREATE_DB);
        info.setStepStatus(1);
        installInfoMapper.addInstallInfo(info);

        result = this.yumAmbariServer(server);
        logger.info("\nyum install ambari-server and agent ：{}", result.getStatus());
        info = new AmbariInstallInfo();
        info.setActive(2);
        info.setAmbariIp(server.getHostIp());
        info.setStepName(AmbariInstallStepName.YUM_AMBARI);
        info.setStepStatus(2);
        installInfoMapper.addInstallInfo(info);

        result = this.scpDatabaseDriver();
        logger.info("\n发送数据库驱动到各主机 ：{}", result.getStatus());
        info.setActive(3);
        info.setAmbariIp(server.getHostIp());
        info.setStepName(AmbariInstallStepName.SCP_DB_DRIVER);
        info.setStepStatus(3);
        installInfoMapper.addInstallInfo(info);

        result = this.installDriver(server);
        logger.info("\nambari-server setup db driver ：{}", result.getStatus());

        result = this.setup(server);
        logger.info("\nambari-server setup：{}", result.getStatus());
        info.setActive(4);
        info.setAmbariIp(server.getHostIp());
        info.setStepName(AmbariInstallStepName.AMBARI_SETUP);
        info.setStepStatus(4);
        installInfoMapper.addInstallInfo(info);

        result = this.initDatabase();
        logger.info("\n初始化ambari数据库 ：{}", result.getStatus());
        info.setActive(5);
        info.setAmbariIp(server.getHostIp());
        info.setStepName(AmbariInstallStepName.AMBARI_DB_INIT);
        info.setStepStatus(5);
        installInfoMapper.addInstallInfo(info);

        result = this.optimize(server);
        logger.info("\n优化ambari ：{}", result);
        info.setActive(6);
        info.setAmbariIp(server.getHostIp());
        info.setStepName(AmbariInstallStepName.AMBARI_OPTIMIZE);
        info.setStepStatus(6);
        installInfoMapper.addInstallInfo(info);

        List<ServerHost> list = serverHostMapper.queryHostList();
        ResultWrapper wrap = new ResultWrapper(info, list);

        return wrap;
    }

    /**
     * <h2>准备数据库及ambari、hive需要的表</h2>
     * <p>
     * 路径是固定的,安装mysql docker时,压缩包里已经包含ambari_sql，也可以在安装mysql时就执行setup.sh初始化ambari库 *
     * </p>
     *
     * @throws Exception
     */
    @PutMapping("/test")
    public ResultWrapper createDatabaseTest() throws Exception {
        App app = getMysqlInfo();
        logger.info(app.toString());

        String cmd = "ip addr";
        String result = ExecuteShell.execCmd(cmd);
        logger.info("result : {}", result);

        cmd = "cat /etc/hosts";
        result = ExecuteShell.execCmd(cmd);
        logger.info("result : {}", result);

        int index = result.indexOf("192.168.152.103 hdp13");
        logger.info("result : {}", index);

        index = result.indexOf("192.168.152.100 hdp10");
        logger.info("result : {}", index);

        index = result.indexOf("192.168.152.100 hdp16");
        logger.info("result : {}", index);

        cmd = "docker ps -a";
        result = ExecuteShell.execCmd(cmd);
        logger.info("result : {}", result);

        return ResultWrapper.successResult();

    }

    /**
     * <h2>ambari优化</h2>
     * <p>
     * <h3>优化以下两个文件</h3>
     * <ul>
     * <ol>
     * <li>1.修改数据库连接编码
     * <p># 文件路径 /etc/ambari-server/conf/ambari.properties
     * <code>server.jdbc.url=jdbc:mysql://hdp1.ambari:3306/ambari<b>?useUnicode=true&characterEncoding=UTF-8</b></code></p>
     * </li>
     * <li>SELECT * FROM "ambari"."repo_definition"
     * <p>替换repo路径</p>
     * </li>
     * </ol>
     * </ul>
     * <code>
     * </code>
     * </p>
     *
     * @throws IOException
     * @author flash aGuang flash8627@hotmail.com 8538191@qq.com 2023/07/14
     */
    @PutMapping("/ambari_opt")
    public ResultWrapper optimize(@RequestBody ServerHost server) throws IOException {

        String optimizeCmd = "ambari_optimization.sh";
        logger.info("ambari optimize......");
        // 登陆到ambari主机
        ShellUtil execute = new ShellUtil(server.getHostIp(), server.getAccount(), server.getPassword(),
                server.getHostPort());

        String cmd = "";
        String result = "";
        String local = String.format("%s/shell/%s", workHome, optimizeCmd);
        String remote = "/tmp";

        App mysql = this.getMysqlInfo();

        // 将安装脚本发送到主机
        JScpUtil.upload(server, local, remote);

        cmd = String.format("cd /tmp && sed -i 's/TEMPLATE_IP/%s/g' %s", mysql.getAppIp(), optimizeCmd);
        logger.info("\ncmd:{}\n", cmd);
        result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);

        cmd = String.format("cd /tmp && sed -i 's/TEMPLATE_PORT/%s/g' %s", mysql.getPort(), optimizeCmd);
        logger.info("\ncmd:{}\n", cmd);
        result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);

        cmd = String.format("cat /tmp/%s", optimizeCmd);
        logger.info("\ncmd:{}\n", cmd);
        result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);

        cmd = String.format("chmod 755 /tmp/%s && /tmp/%s", optimizeCmd, optimizeCmd);
        logger.info("ambari optimize cmd:{}", cmd);
        result = execute.executeForResult(cmd);
        logger.info("ambari optimize result:{}", result);

        cmd = String.format("rm -rf /tmp/%s", optimizeCmd, optimizeCmd);
        logger.info("ambari optimize cmd:{}", cmd);
        result = execute.executeForResult(cmd);
        logger.info("ambari optimize result:{}", result);

        ServerHost record=new ServerHost();
        record.setIsAmbariServerOptimize(1);
        record.setId(server.getId());
        serverHostMapper.updateAmbariStatus(record);

        return ResultWrapper.successResult();
    }

    /**
     * <h2>准备数据库及ambari、hive需要的表--这里注意是root帐户</h2>
     * <p>
     * 路径是固定的,安装mysql docker时,压缩包里已经包含ambari_sql，也可以在安装mysql时就执行setup.sh初始化ambari库 *
     * </p>
     *
     * @throws Exception
     */
    @PutMapping("/db/create")
    public ResultWrapper createDatabase() throws Exception {
        App app = getMysqlInfo();
        logger.info("\ndb create mysql app:\n{}\n", app.toString());

        String filePath = String.format("%s/ambari_sql/create_database_table.sql", workHome);
        logger.info("\nexecute sql filePath:{}\n", filePath);
        app.setUsername("root");
        app.setPassword(rootDBPassword);
        int result = SQLScriptExecutor.execute(filePath, app);
        logger.info("\nexecute sql result:{}\n", result);

        String sql = "select user from mysql.user";
        List<DatabaseSchema> list = SQLScriptExecutor.exeQuery(sql, app);
        logger.info("\nexecute sql result:\n{}\n", list.toString());

        sql = "show databases";
        list = SQLScriptExecutor.exeQuery(sql, app);
        logger.info("\nexecute sql result:\n{}\n", list.toString());

        return ResultWrapper.successResult("success", list);

    }

    /**
     * <h2>初始化ambari表--这里注意是ambari帐户</h2>
     * <p>
     * 路径是固定的,安装mysql docker时,压缩包里已经包含ambari_sql，也可以在安装mysql时就执行setup.sh初始化ambari库 *
     * </p>
     *
     * @throws Exception
     */
    @PutMapping("/db/init")
    public ResultWrapper initDatabase() throws Exception {
        App app = getMysqlInfo();
        logger.info("db init mysql app:\n{}\n", app.toString());

        String filePath = String.format("%s/ambari_sql/Ambari-DDL-MySQL-CREATE.sql", workHome);

        String localIp = LinuxIPUtil.getLinuxLocalIp();
        logger.info("\n=========================>:{}\n", localIp);

        //ShellUtil execute = new ShellUtil(host.getHostIp(), host.getAccount(), host.getPassword(), host.getHostPort());

        int result = SQLScriptExecutor.execute(filePath, app);
        logger.info("execute sql result:{}", result);
        
        ServerHost server = serverHostMapper.queryHostByIp(app.getAppIp());
        
        ServerHost record=new ServerHost();
        record.setIsAmbariDBInit(1);
        record.setId(server.getId());
        serverHostMapper.updateAmbariStatus(record);
       
        return ResultWrapper.successResult("ambari database init successfull");

    }

    /**
     * <h2>:安装ambari server</h2>
     * <p>
     * <ul>
     * <ol>
     * <li>简单的执行yum -y install ambari-client && ambari-agent restart即可</li>
     * </ol>
     * </ul>
     * </p>
     */
    @PutMapping("/yum")
    public ResultWrapper yumAmbariServer(@RequestBody ServerHost server) {

        ShellUtil execute = new ShellUtil(server);

        String cmd = "yum -y install ambari-server";
        logger.info("\nambari-server \n cmd ：{} \n", cmd);
        String result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);

        App app = new App();
        app.setAppIp(server.getHostIp());
        app.setAppName(AppConstruct.AMBARI_SERVER);
        app.setAppType(AppTypeConstruct.SYSTEM_TOOL);
        appMapper.addApp(app);

        List<ServerHost> records = serverHostMapper.queryHostList();
        ServerHost record=null;
        for (ServerHost host : records) {
            execute = new ShellUtil(host);

            cmd = "yum -y install ambari-agent";
            result = execute.executeForResult(cmd);
            logger.info("\nresult:{}\n", result);

            record=new ServerHost();
            record.setIsAmbariClientFlag(1);
            if(server.getHostIp().equals(host.getHostIp())){
            	record.setIsAmbariFlag(1);
            }
            
            record.setId(host.getId());
            serverHostMapper.updateAmbariStatus(record);
            
            execute.close();
        }

        return ResultWrapper.successResult();

    }

    /**
     * <h2>分发数据库驱动</h2>
     * <p>将驱动发到集群各主机
     * </p>
     *
     * @throws IOException
     */
    @PutMapping("/driver")
    public ResultWrapper scpDatabaseDriver() throws IOException {

        ShellUtil execute = null;
        String cmd = "";
        String result = "";

        final String local = String.format("%s/app/%s", workHome, DRIVER_NAME);
        logger.info("\nresult:{}\n", result);

        logger.info("\n============================================================>\n");

        List<ServerHost> records = serverHostMapper.queryHostList();
        ServerHost record=null;
        for (ServerHost host : records) {
            execute = new ShellUtil(host);
            cmd = String.format("mkdir -p %s", DRIVER_PATH);
            logger.info("\ncmd:{}\n", cmd);
            result = execute.executeForResult(cmd);
            logger.info("\nresult:{}\n", result);

            // 将安装文件压缩包分发到集群各主机
            JScpUtil.upload(host, local, "/tmp");

            cmd = String.format("\\cp -rf /tmp/%s %s", DRIVER_NAME, DRIVER_PATH);
            logger.info("\ncmd:{}\n", cmd);
            result = execute.executeForResult(cmd);

            cmd = String.format("rm -rf /tmp/%s ", DRIVER_NAME);
            result = execute.executeForResult(cmd);
            logger.info("\n移除驱动 cmd ：{}", cmd);

            cmd = String.format("chmod -R o+rx /usr/java %s", DRIVER_PATH);
            logger.info("\ncmd:{}\n", cmd);
            result = execute.executeForResult(cmd);
            
            record=new ServerHost();
            record.setIsAmbariDBDriverFlag(1);
            record.setId(host.getId());
            serverHostMapper.updateAmbariStatus(record);

        }
        execute.close();

        return ResultWrapper.successResult();

    }

    /**
     * <h2>ambari-server setup --jdbc-db</h2>
     * <p>ambari-server setup --jdbc-db=mysql --jdbc-driver=/path
     * </p>
     *
     * @throws IOException
     */
    @PutMapping("/setup_driver")
    public ResultWrapper installDriver(@RequestBody ServerHost server) throws IOException {

        logger.info("\n============================================================>\n");

        ShellUtil execute = new ShellUtil(server);
        String cmd = String.format("ambari-server setup --jdbc-db=mysql --jdbc-driver=%s/%s", DRIVER_PATH, DRIVER_NAME);
        logger.info("\ncmd:{}\n", cmd);
        String result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);
        execute.close();
        logger.info("\n<============================================================\n");

        return ResultWrapper.successResult();

    }

    /**
     * <h2>执行ambari-server setup初始化--这里注意库是root帐户</h2>
     * <p>
     * </p>
     *
     * @throws IOException
     */
    @PutMapping("/setup")
    public ResultWrapper setup(@RequestBody ServerHost server) throws Exception {

        logger.info("start setup......");
        // 登陆到ambari主机
        ShellUtil execute = new ShellUtil(server.getHostIp(), server.getAccount(), server.getPassword(),
                server.getHostPort());

        String shName = "ambari-server_setup.sh";
        String cmd = "";
        String result = "";
        String local = String.format("%s/shell/%s", workHome, shName);
        String remote = "/opt";
        String remoteFile = String.format("%s/%s", remote, shName);

        // 将安装脚本发送到主机
        JScpUtil.upload(server, local, remote);

        cmd = String.format("cd /opt && chmod o+x %s", shName);
        logger.info("\ncmd:{}\n", cmd);
        result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);

        App mysql = this.getMysqlInfo();

        cmd = String.format("sed -i 's/TEMPLATE_IP/%s/g' %s", mysql.getAppIp(), remoteFile);
        logger.info("\ncmd:{}\n", cmd);
        result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);

        cmd = String.format("sed -i 's/TEMPLATE_PORT/%s/g' %s", mysql.getPort(), remoteFile);
        logger.info("\ncmd:{}\n", cmd);
        result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);

        cmd = String.format("sed -i 's/TEMPLATE_PWD/%s/g' %s", mysql.getPassword(), remoteFile);
        logger.info("\ncmd:{}\n", cmd);
        result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);

        cmd = String.format("cd /opt && ./%s", shName);
        logger.info("\ncmd:{}\n", cmd);
        result = execute.executeForResult(cmd);
        logger.info("\nresult:{}\n", result);

        //将server.ambari添加到各主机hosts
        installHosts(server.getHostIp());
        
        ServerHost record=new ServerHost();
        record.setIsAmbariSetupFlag(1);
        record.setId(server.getId());
        record.setHostIp(server.getHostIp());
        serverHostMapper.updateAmbariStatus(record);

        return ResultWrapper.successResult(result);

    }

    /**
     * <h2>Uninstalling cluster</h2>
     */
    @PutMapping("/uninstall")
    public ResultWrapper uninstallCluster() throws IOException {
        logger.info("\nuninstall Ambari Cluster");
        List<ServerHost> hosts = serverHostMapper.queryHostList();
        String cmd = "";
        ShellUtil execute = null;
        String result = null;
        String fileName = "ambari_uninstall.sh";
        String local = String.format("%s/shell/%s", workHome, fileName);

        AmbariInstallInfo info = new AmbariInstallInfo();
        App mysql = getMysqlInfo();
        ServerHost record=null;
        
        for (ServerHost host : hosts) {
        	
        	record=new ServerHost();
            Integer isAmbariFlag = host.getIsAmbariFlag();
            boolean flag = (isAmbariFlag != null && isAmbariFlag == 1);
            logger.info("\n>>>>>>>>>Is Ambari Flag:{} \nand status:{}\n", host.getIsAmbariFlag(),flag);

            if (flag) {
                cmd = "ambari-server stop";
                execute = new ShellUtil(host);
                logger.info("\nambari-server script copy cmd:{}\n", cmd);
                result = execute.executeForResult(cmd);
                
                record.setIsAmbariFlag(2);
                record.setIsAmbariSetupFlag(2);
                record.setIsAmbariServerOptimize(2);

                info.setAmbariIp(host.getHostIp());
            }

            if(mysql.getAppIp().equals(host.getHostIp())){
                record.setIsAmbariDBInit(2);
            }

            JScpUtil.upload(host, local, "/tmp");

            cmd = String.format("chmod o+x /tmp/%s && /tmp/%s", fileName, fileName);
            execute = new ShellUtil(host);
            logger.info("\n ============= > script execute cmd:{}\n", cmd);
            result = execute.executeForResult(cmd);
            //logger.info("\n ========== > script execute result:{}\n", result);

            cmd = String.format("rm -rf /tmp/%s", fileName);
            logger.info("\n ============= > script execute cmd:{}\n", cmd);
            result = execute.executeForResult(cmd);
            logger.info("\n ========== > script execute result:{}\n", result);

            record.setIsAmbariDBDriverFlag(2);
            record.setIsAmbariClientFlag(2);
            record.setHostIp(host.getHostIp());
            record.setId(host.getId());
            serverHostMapper.updateAmbariStatus(record);
            logger.info("\n>>>>>>>>>Is update host:{}\n", record);

        }

        installInfoMapper.deleteInstallInfo(info);
        execute.close();
        return ResultWrapper.successResult(toResltHosts(hosts,mysql.getAppIp(),info.getAmbariIp()));
    }
    
    /**
     * <h2>uninstall result data<h2>
     * @param hosts
     * @param mysqlIp
     * @param ambariIp
     * @return
     */
    private List<ServerHost> toResltHosts(List<ServerHost> hosts,String mysqlIp,String ambariIp){
    	
    	List<ServerHost> recodes = new ArrayList<ServerHost>();
    	for (ServerHost host : hosts) {
    		if(ambariIp.equals(host.getHostIp())) {
    			host.setIsAmbariFlag(2);
        		host.setIsAmbariSetupFlag(2);
        		host.setIsAmbariServerOptimize(2);
    		}
            
    		if(mysqlIp.equals(host.getHostIp())){
    			host.setIsAmbariDBInit(2);
            }
    		
    		host.setIsAmbariDBDriverFlag(2);
    		host.setIsAmbariClientFlag(2);
    		
    		recodes.add(host);
		}
    	
    	return recodes;
    }

     private App getMysqlInfo() {
        return appMapper.queryAppName(AppConstruct.MYSQL_APP);
    }

    /**
     * <h2>安装 mysql 或 httpd 主机 hosts</h2>
     */
    private void installHosts(String ip) throws Exception {

        String localIp = LinuxIPUtil.getLinuxLocalIp();
        String hostName = "server";

        String cmd = "";
        final String fileName = "hosts.sh";
        final String templateName = String.format("%s-template", fileName);
        final String local = String.format("%s/shell/%s", workHome, templateName);

        ServerHost server = serverHostMapper.queryHostByIp(localIp);
        ShellUtil execute = new ShellUtil(server);
        String result = null;

        //覆盖拷贝
        cmd = String.format("\\cp -rf %s/shell/%s-src %s", workHome, fileName, local);
        logger.info("\n script copy cmd:{}\n", cmd);
        result = execute.executeForResult(cmd);

        //替换验证的IP
        cmd = String.format("sed -i 's/template_ip/%s/g' %s", ip, local);
        logger.info("\n hosts cmd:{}\n", cmd);
        result = execute.executeForResult(cmd);

        //替换验证的主机名
        cmd = String.format("sed -i 's/template_hostname/%s.ambari/g' %s", hostName, local);
        logger.info("\n hosts cmd:{}\n", cmd);
        result = execute.executeForResult(cmd);

        cmd = String.format("sed -i '8i%s %s.ambari' %s", ip, hostName, local);
        logger.info("\n sed hosts cmd:{}\n", cmd);
        result = execute.executeForResult(cmd);

        List<ServerHost> records = serverHostMapper.queryHostList();

        for (ServerHost host : records) {
            JScpUtil.upload(host, local, "/tmp");

            execute = new ShellUtil(host);
            cmd = String.format("\\cp -rf /tmp/%s /opt/%s", templateName, fileName);
            logger.info("\n hosts cmd:{}\n", cmd);
            // 执行命令
            result = execute.executeForResult(cmd);

            cmd = String.format("chmod o+x /opt/%s && /opt/%s", fileName, fileName);
            logger.info("\n 执行脚本文件:{}\n", cmd);
            result = execute.executeForResult(cmd);
            logger.info("\n hosts result:{}\n", result);

            cmd = String.format("rm -rf /opt/%s", fileName, fileName);
            logger.info("\n 执行脚本文件:{}\n", cmd);
            result = execute.executeForResult(cmd);
            logger.info("\n hosts result:{}\n", result);

        }

        execute = new ShellUtil(server);
        cmd = String.format("rm -rf /tmp/%s", templateName);
        logger.info("\n 执行脚本文件:{}\n", cmd);
        result = execute.executeForResult(cmd);
        logger.info("\n hosts result:{}\n", result);

    }
}
